package bulkyshare.project.de.bulkyshare.activities;

import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

import bulkyshare.project.de.bulkyshare.R;
import bulkyshare.project.de.bulkyshare.container.Termin;
import bulkyshare.project.de.bulkyshare.dialogs.DistanceChooserDialog;
import bulkyshare.project.de.bulkyshare.tasks.TaskHandler;
import bulkyshare.project.de.bulkyshare.views.TwoRowedListViewAdapter;

/**
 * @author Alexander Radtke
 * @version 1.0
 *
 * This class is the first View/Fragment to be shown after the login.
 * This class shows all pickup dates nearby depending on distance restrictions, that were set by the
 * user.
 * By touching an item the detail view of the item is displayed in an extra Activity.
 */
public class PickupDatesNearby extends Fragment implements AdapterView.OnItemClickListener,
        LocationListener {
    private List<Termin> termine;
    private ListView listView;
    private TwoRowedListViewAdapter listAdapter;
    private LocationManager location;
    private Location current;
    private TaskHandler taskHandler;
    private String user_id;

    // Refresh after a minimal time interval of 5 minutes
    private final static int MIN_TIME_TO_UPDATE = 300000;
    // Refresh after a minimal distance value of 100 meters
    private final static int MIN_DISTANCE_TO_UPDATE = 100;
    // Variable to limit the search radius.
    private double MAX_DISTANCE;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.pickup_dates_nearby, container, false);
        setHasOptionsMenu(true);
        // Load the maximal search radius from the SharedPreferences
        loadMaxDistance();

        Bundle b = getArguments();
        if (b != null)  {
            user_id = b.getString("user_id");
        }

        location = (LocationManager)getActivity().getSystemService(Context.LOCATION_SERVICE);
        termine = new ArrayList<Termin>();
        listView = (ListView) view.findViewById(R.id.collection_date_list);
        listAdapter = new TwoRowedListViewAdapter(getActivity(), termine);
        listView.setAdapter(listAdapter);
        // Check if the GPS is activated if its not active open a Dialog
        if (!isGpsActive(location)) {
            activateGps();
        // Otherwise request a location update and calculate the distances for all pickup dates from the database
        } else {
            location.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_TO_UPDATE, MIN_DISTANCE_TO_UPDATE, this);
            current = location.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            calculateDistance();
        }

        listView.setOnItemClickListener(this);
        return view;
    }

    /**
     * When this Fragment gets active check if the GPS is active. If it is active,
     * request a location update and update the location if the user moved far enough.
     */
    @Override
    public void onResume() {
        super.onResume();
        if (!isGpsActive(location)) {
            activateGps();
        } else {
            location.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_TO_UPDATE, MIN_DISTANCE_TO_UPDATE, this);
            current = location.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        }
    }

    /**
     * If this View is paused remove the location updates to save battery life
     */
    @Override
    public void onPause() {
        super.onPause();
        location.removeUpdates(this);
    }

    /**
     * This class Handles a click on a ListView item.
     * If you click on one item you will be forwarded to the detail View of the item.
     */
    @Override
    public void onItemClick(AdapterView adapterView, View view, int pos, long id) {
            Log.d("Position: ", new Integer(pos).toString());
            // forward to detail View
            Intent intent = new Intent(getActivity(), PickupDateDetail.class);
            intent.putExtra("termin_object", termine.get(pos));
            intent.putExtra("name", getActivity().getActionBar().getTitle());
            startActivity(intent);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // inflate the action bar and add elements to it
        inflater.inflate(R.menu.collection_dates_nearby_menu, menu);
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle selected action bar item event
        switch (item.getItemId()) {
            case R.id.action_settings:
                DistanceChooserDialog distanceChooserDialog = new DistanceChooserDialog(getActivity());
                distanceChooserDialog.show();
                distanceChooserDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
                    @Override
                    public void onDismiss(DialogInterface dialogInterface) {
                        loadMaxDistance();
                        calculateDistance();
                    }
                });
                return true;
            // Refresh action button was pressed
            case R.id.action_refresh:
                if (!isGpsActive(location)) {
                    activateGps();
                } else {
                    // Update the location and recalculate the distances
                    if (current != null) {
                        Log.d("latitude", new Double(current.getLatitude()).toString());
                        Log.d("longitude", new Double(current.getLongitude()).toString());
                        calculateDistance();
                    }
                }
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    /**
     * This Method calculates all distances for all Termine from the database.
     * It also adds them to the ListView and updates it.
     */
    private void calculateDistance() {
        try {
            taskHandler = new TaskHandler(getActivity());
            taskHandler.setPara(new int[]{Integer.parseInt(user_id)});
            List<Termin> db = (List<Termin>) taskHandler.execute("getAllTermine").get();
            // Clear so that no double values exist
            termine.clear();
            for (int i = 0; i < db.size(); i++) {
                // Distance can only be calculated with two Location objects
                // so create one with the data from the database
                Location end = new Location(Context.LOCATION_SERVICE);
                end.setLongitude(db.get(i).getLongitude());
                end.setLatitude(db.get(i).getLatitude());
                // Calculates the distance and returns it in meters
                double result = current.distanceTo(end);
                // Convert result to kilometer
                result = result / 1000;
                // Round to x.x km
                result = Math.rint(result * 10) / 10;
                Log.d("result", new Float(result).toString());
                // set the distance and add the Termin to the ListView
                db.get(i).setDistance(result);
                // Only add pickup dates which distance is smaller than the maximal search range
                // the user specified
                if (db.get(i).getDistanceDouble() <= MAX_DISTANCE) {
                    termine.add(db.get(i));
                }
            }
            // request ListView update because some items changed
            listAdapter.notifyDataSetChanged();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Checks if the user has GPS enabled.
     * @param locationManager The LocationManager object, that contains the Location System Service
     * @return True if GPS is enabled
     */
    private boolean isGpsActive(LocationManager locationManager) {
        if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            return true;
        }
        return false;
    }

    /**
     * Starts a dialog which redirects the user the Settings page. Where he is able to activate
     * his GPS Service.
     */
    private void activateGps() {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle(R.string.activate_gps);
        builder.setMessage(R.string.activate_message);
        builder.setCancelable(false);
        builder.setPositiveButton(R.string.activate, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
                dialogInterface.cancel();
            }
        });
        AlertDialog alert = builder.create();
        alert.show();
    }

    /**
     * Load the maximal search range from the SharedPreferences. If there is no saved value
     * set it to the default of 25 kilometers.
     */
    private void loadMaxDistance() {
        SharedPreferences preferences = getActivity().getPreferences(Context.MODE_PRIVATE);
        float default_distance = (float)getResources().getInteger(R.integer.default_distance);
        MAX_DISTANCE = (double)preferences.getFloat("max_distance", default_distance);
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }

    /**
     * If a location change occurred set the old location to the new location
     * @param loc The current location object
     */
    @Override
    public void onLocationChanged(Location loc) {
        if (location != null) {
            current = loc;
            // Create a message if a new location is available
            String message = String.format("Neue Koordinaten\nLongitude: %1$s\nLatitude: %2$s",
                    loc.getLongitude(), loc.getLatitude());
            Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show();
            // Recalculate distance if coordinates changed
            calculateDistance();
        }
    }

    @Override
    public void onProviderEnabled(String provider) {
        //Toast.makeText(getActivity(), "Provider: " + provider + " is enabled!", Toast.LENGTH_LONG).show();
    }

    @Override
    public void onProviderDisabled(String provider) {
        //Toast.makeText(getActivity(), "Provider: " + provider + " is disabled!", Toast.LENGTH_LONG).show();
    }
}
